package org.ecloud.oauth.server.provider;

import java.util.concurrent.TimeUnit;

import org.ecloud.common.constants.StateEnum;
import org.ecloud.core.entity.APIResult;
import org.ecloud.oauth.constants.RedisKey;
import org.ecloud.oauth.server.entity.ClientVo;
import org.ecloud.redis.utils.RedisUtil;
import org.ecloud.utils.BeanUtil;
import org.ecloud.utils.StringUtil;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

/** 
 * auth2.0 授权控制器
 * 
 *<pre>
 * 添加数据源配置，指向client数据库，获取已登记应用。
 * 已登记应用才能使用授权服务 
 *</pre>
 */
@Api(tags = "认证中心", value = "授权")
@RestController
@RequestMapping("/authorize")
public class AuthorizeProvider extends BaseProvider {
	
	/*
	----------------------------------------------------------------- 
	请求参数
 	参数名			必选		类型及范围	说明
	client_id		true	string	申请应用时分配的AppKey。
	redirect_uri	true	string	授权回调地址，站外应用需与设置的回调地址一致，站内应用需填写canvas page的地址。
	scope			false	string	申请scope权限所需参数，可一次申请多个scope权限，用逗号分隔。
	state			false	string	用于保持请求和回调的状态，在回调时，会在Query Parameter中回传该参数。开发者可以用这个参数验证请求有效性，也可以记录用户请求授权页前的位置。这个参数可用于防止跨站请求伪造（CSRF）攻击
	display			false	string	授权页面的终端类型，取值见下面的说明。
	forcelogin		false	boolean	是否强制用户重新登录，true：是，false：否。默认false。
	language		false	string	授权页语言，缺省为中文简体版，en为英文版。英文版测试中，开发者任何意见可反馈至 @微博API
	-----------------------------------------------------------------
	display说明：
	参数取值		类型说明
	default		默认的授权页面，适用于web浏览器。
	mobile		移动终端的授权页面，适用于支持html5的手机。注：使用此版授权页请用 https://open.weibo.cn/oauth2/authorize 授权接口
	wap			wap版授权页面，适用于非智能手机。
	client		客户端版本授权页面，适用于PC桌面应用。
	apponweibo	默认的站内应用授权页，授权后不返回access_token，只刷新站内应用父框架。
	-----------------------------------------------------------------
	返回数据
	返回值字段	字段类型	字段说明
	code	string	用于第二步调用oauth2/access_token接口，获取授权后的access token。
	state	string	如果传递参数，会回传该参数。
	-----------------------------------------------------------------
	示例
	//请求
	https://api.weibo.com/oauth2/authorize?client_id=123050457758183&redirect_uri=http://www.example.com/response&response_type=code
	//同意授权后会重定向
	http://www.example.com/response&code=CODE
	*/
	
	/**
	 * 获取授权码
	 * 
	 *<pre>
	 * https://api.weibo.com/oauth2/authorize?
	 * 		client_id=YOUR_CLIENT_ID&
	 * 		response_type=code&
	 * 		redirect_uri=YOUR_REGISTERED_REDIRECT_URI
	 *</pre>
	 * 
	 * @return
	 */
	@ApiOperation(value = "申请授权", notes = "传入授权AppKey，申请授权")
	@RequestMapping(value = "", method = {RequestMethod.GET, RequestMethod.POST})
	public APIResult<String> authorize(
			@ApiParam(name = "client_id", value = "申请应用时分配的AppKey", required = true) @RequestParam(name = "client_id", required = true) String clientId, 
			@ApiParam(name = "login_state", value = "用户登录后返回的状态码", required = true) @RequestParam(name = "login_state", required = true) String loginState, 
			@ApiParam(name = "redirect_uri", value = "授权回调地址", required = false) @RequestParam(name = "redirect_uri", required = false) String redirectUri,
			@ApiParam(name = "scope", value = "申请scope权限所需参数，可一次申请多个scope权限，用逗号分隔", required = false) @RequestParam(name = "scope", required = false) String scope, 
			@ApiParam(name = "state", value = "用于保持请求和回调的状态", required = false) @RequestParam(name = "state", required = false, defaultValue = "#d*9^n") String state, 
			@ApiParam(name = "auto_approve", value = "自动授权，不跳转到授权页面", required = false) @RequestParam(name = "auto_approve", required = false, defaultValue = "true") boolean autoApprove, 
			@ApiParam(name = "display", value = "授权页面的终端类型", required = false) @RequestParam(name = "display", required = false, defaultValue = "default") String display,
			@ApiParam(name = "forcelogin", value = "是否强制用户重新登录", required = false) @RequestParam(name = "forcelogin", required = false, defaultValue = "false") boolean forcelogin
			){
		logger.debug("request authorize");
		APIResult<String> result = new APIResult<>();
		result.addVariable("state", state);
		
		try{
			ClientVo client = clientService.getByClientId(clientId);
			if(BeanUtil.isEmpty(client)){
				result.setCode(StateEnum.ILLEGAL_CLIENT_ID_SECRET.getCode());
				throw new RuntimeException("授权不存在");
			}
			
			String lskey = appConfig.getRedisKey(RedisKey.LOGIN_STATE, loginState);
			if(!RedisUtil.redisTemplateString.hasKey(lskey)){
				result.setCode(StateEnum.ILLEGAL_LOGIN_STATE.getCode());
				throw new RuntimeException("用户未登录");
			}
			
			String username = RedisUtil.redisTemplateString.opsForValue().get(lskey);
			if(StringUtil.isBlank(username)){
				result.setCode(StateEnum.ILLEGAL_LOGIN_STATE.getCode());
				throw new RuntimeException("用户未登录");
			}
			
			String code = uuid();
			result.setData(code);
			
			// 删除登录状态码
			RedisUtil.redisTemplateString.delete(lskey);
			// 存入redis
			String key = appConfig.getRedisKey(RedisKey.AUTHORIZE_CODE, code);
			RedisUtil.redisTemplate.opsForHash().put(key, RedisKey.CLIENT_ID, clientId);
			RedisUtil.redisTemplate.opsForHash().put(key, RedisKey.USER_NAME, username);
			RedisUtil.redisTemplate.expire(key, tokenConfig.getAcexpires(), TimeUnit.SECONDS);
		}catch(Exception e){
			if(StateEnum.SUCCESS.getCode() == result.getCode()){
				result.setCode(StateEnum.ILLEGAL_CLIENT_ID_SECRET.getCode());
			}
			//result.setMessage("");
			result.setCause(e.getMessage());
			logger.error("authorize failed:", e);
		}
		
		return result;
	}
	
}
